/*
 * Assignment 6                  P6.java                  Due July 24, 2011
 *
 * login: cs11ubn
 */

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

/**
 * Creates a window with a JComboBox that draws several shapes.
 *
 * Methods:
 *  init()
 *  paint()
 *  itemStateChanged
 *  mouseClicked()
 *  mouseEntered()
 *  mouseExited()
 *  mousePressed()
 *  mouseReleased()
 *  mouseDragged()
 *  mouseMoved()
 *
 * @author Michael Robinette (cs11ubn)
 * @version 1.0.1
 */
public class P6 extends JApplet implements MouseListener, MouseMotionListener,
  ItemListener
{
  private final int NO_VALUE = 0; // This is just for easier reading
  private final int FONT_SIZE = 12; // Holds the size of the font
  private final int OFFSET_Y = 5; // Offset for displaying text on the box
  private final int OFFSET_X = 65; // Offset for displaying text on the box
  private int x1, x2, y1, y2; // X and Y variables that hold the box
  private int x3[], y3[]; // Array of points for the polygon
  private JComboBox combo; // Combo box for selecting a shape
  private int shape; // NO_VALUE for no shape
  private String[] comboChoices = {"Select", "Oval", "Arc", "Line",
      "Rounded Rectangle", "Polygon"}; // Array of the options in the combobox

  /**
   * Called when our applet is created. We setup all of our variables here.
   *
   * @see javax.swing.JApplet
   */
  public void init()
  {
    x1 = x2 = y1 = y2 = 0; // Set all of our points to 0
    x3 = new int[5]; // Setup our arrays
    y3 = new int[5];
    shape = NO_VALUE; // Using 0 as no shape

    // Set the flow layout to be centered
    setLayout(new FlowLayout(FlowLayout.CENTER)); // Default for applet

    // Add this as the mouse and mouse motion listener for the applet
    addMouseListener(this);
    addMouseMotionListener(this);

    // Setup the combobox
    combo = new JComboBox(comboChoices);
    combo.addItemListener(this); // Set us as the item listener for any change

    // Add it to the applet
    add(combo);
  }

  /**
   * Paint method called by the applet. Calls the superclass to draw the heavy
   * weight components, then displays the selected shape/polygon/thing. Uses
   * a hacked together gradient color switcher for the oval, arc, and the
   * rounded rectangle.
   *
   * @see javax.swing.JApplet
   * @see java.awt.Graphics
   * @see java.awt.Color
   * @see java.awt.Polygon
   * @see java.awt.Font
   */
  public void paint(Graphics g)
  {
    // Declare our variables. Yay for smart variable names
    int smallest, largest;
    double step;

    // Call JApplets paint
    super.paint(g);

    // Set the font
    g.setFont(new Font("Serif", Font.ITALIC + Font.BOLD, FONT_SIZE));

    // Draw the bounding square and Start/End lables
    if (x1 != x2 && y2 - y1 > 0 && x2 - x1 > 0)
    {
      // Start lable right above the first point
      g.drawString("Start Here", x1, y1 - OFFSET_Y);
      g.drawRect(x1, y1, x2 - x1, y2 - y1); // Bounding rectangle
      // End lable shifted down and left so as to not cover the box.
      // Need to find a more elegant way to do this rather than hardcode
      g.drawString("End Here", x2 - OFFSET_X, y2 + FONT_SIZE + OFFSET_Y);
    }

    // Begin the hacking, grab the largest and smallest for possible use
    if ((x2 - x1) < (y2 - y1))
    {
      smallest = x2 - x1;
      largest = y2 - y1;
    }
    else
    {
      smallest = y2 - y1;
      largest = x2 - x1;
    }

//    largest /= 4;

    // Only draw if the smallest is non-zero. If it is then you wouldn't be
    // able to see it anyway
    if (smallest == 0)
      return;
    else
      step = ((double)255) / largest; // Grab our step size for the color

    double yMod, xMod;

    if (smallest == (y2 - y1))
    {
      xMod = 1;
      yMod = (double)smallest / largest;
    }
    else
    {
      xMod = (double)smallest / largest;
      yMod = 1;
    }

    // Loop through each pixle from 0 to the smallest
    for (int i = 0; i <= smallest; i++)
    {
      /*Set the color to the step size multiplied by the current pixle
      distance then modify for a more general color scheme. The way it is set
      up now will range from black around the edges to a center color that is
      gold-yellow-orange-ish*/
      g.setColor(new Color((int)Math.round(step * i),
          (int)Math.round((step * i) / 2),
          (int)Math.round(step * i / 5)));

      // Switch the shape (0-5) and draw the needed shape
      switch (shape)
      {
        case NO_VALUE: // No shape
          break;
        case 1: // Oval
//        g.drawString("Oval", 40, 50);
          /*Fill an oval with these offsets so as to fill from the outside in
          We have to keep moving the x and y coords because the whole oval
          is shrinking*/
          g.fillOval(x1 + (i / 2), y1 + (i / 2), x2 - x1 - i, y2 - y1 - i);
          break;
        case 2: // Arc
          //g.drawString("Arc", 40, 50);
          /*Here we draw two arcs, one from 0 degrees to 90, the other from
          180 to 270. Something odd happens if you tweak it, as the center of
          the box will start to smush from both of the arcs*/
          g.fillArc(x1 + (i / 2), y1 + (i / 2),
              x2 - x1 - i, y2 - y1 - i, 0, 90);
          g.fillArc(x1 + (i / 2), y1 + (i / 2),
              x2 - x1 - i, y2 - y1 - i, 180, 90);
          break;
        case 3: // Line
//          g.drawString("Line", 40, 50);
          /*Draw a line and color it based on its pixle distance*/

          g.drawLine((int) Math.round(x1 + i * xMod),
              (int) Math.round(y1 + i * yMod),
              (int) Math.round(x2 - i * xMod),
              (int) Math.round(y2 - i * yMod));
          break;
        case 4: // Rounded Rectangle
//          g.drawString("Rounded Rectangle", 40, 50);
          /*Here we draw a rounded rectangle with the edges arc width and
          height decided by the distance of the pixle, as well as the overall
          size of the the shape. This allows us to have it dynamically change
          the corners based on the size of the bounding box. It also fades
          colors really nicely*/
          g.fillRoundRect(x1 + (i / 2), y1 + (i / 2),
              x2 - x1 - i, y2 - y1 - i, (x2 - x1 - i) / 2,
              (y2 - y1 - i) / 2);
          break;
        case 5: // Polygon
//          g.drawString("Polygon", 40, 50);
          /*Here we make a polygon object, set all of its points, and then
          have graphics draw it to screen. Still thinking of a way to overdo
          this part.*/

          // Make the polygon
          Polygon polly = new Polygon();

          // Iterate through the points x3, y3 and set them in the polygon
          for (int iter = 0; iter < x3.length; iter++)
          {
            polly.addPoint(x3[iter], y3[iter]); // Add the point
          }

          // Fill it on screen
          g.fillPolygon(polly);

          /*Because we are only drawing a polygon in one move we can go ahead
          and say that we are done with the method. So we return out. Note
          there is no value returned, as this method as a return type of null.
          */
          return;
        default:
          break;
      }
    }
  }

  /**
   * Grabs the event from the combobox. Called when a user selects a new shape
   *
   * @see java.awt.event
   */
  public void itemStateChanged(ItemEvent event)
  {
    shape = combo.getSelectedIndex(); // Grab the shape selected
    repaint(); // Repaint the screen for the given shape
  }

  /**
   * Grabs the location where the user presses down the mouse button and
   * stores it into x1 and y1. Calls the repaint to get rid of the last shape.
   *
   * @see java.awt.event
   */
  public void mousePressed(MouseEvent event)
  {
    x1 = event.getX(); // Grab the x
    y1 = event.getY(); // Grab the y

    repaint(); // Repaint
  }

  /**
   * Grabs the point the user let go of the mouse button and stores it in x2,
   * y2. At this point it also updates the array of polygon points with the
   * new values.
   *
   * @see java.awt.event
   */
  public void mouseReleased(MouseEvent event)
  {
    x2 = event.getX(); // Grab the x
    y2 = event.getY(); // Grab the y

    // Update the polygons x points
    x3[0] = x1;
    x3[1] = x2;
    x3[2] = x1;
    x3[3] = x2;
    x3[4] = x1;

    // Update the polygons y points
    y3[0] = y1;
    y3[1] = y1;
    y3[2] = y2;
    y3[3] = y2;
    y3[4] = y1;

    repaint(); // Repaint to display the current shape
  }

  /**
   * Here we perform the same action as a mouse release so we can have the
   * shape change size as we are dragging the mouse around.
   *
   * @see java.awt.event
   */
  public void mouseDragged(MouseEvent event)
  {
    mouseReleased(event); // Just pass the event to the mouseReleased method
  }

  /**
   * This method updates the mouses x and y location in the status bar each
   * time the mouse moves
   *
   * @see java.awt.event
   */
  public void mouseMoved(MouseEvent event)
  {
    // Write the current position to the status bar
    showStatus("(" + event.getX() + ", " + event.getY() + ")");
  }

  /**
   * Method stub for mouseClicked
   *
   * @see java.awt.event
   */
  public void mouseClicked(MouseEvent event) {}

  /**
   * Method stub for mouseEntered
   *
   * @see java.awt.event
   */
  public void mouseEntered(MouseEvent event) {}

  /**
   * Method stub for mouseExited
   *
   * @see java.awt.event
   */
  public void mouseExited(MouseEvent event) {}
}
